#!/usr/bin/env python
#
#
#
# Uses the pyAmazon Amazon Web Service API wrapper maintained by 
# Michael Josephson.
# [http://www.josephson.org/projects/pyamazon/]
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.

import optparse #configure the script by the command line
import amazon   #how we talk to amazon
import string
import re
import conf_file #a separate util file i have for reading various config files
import xml.parsers.expat #to trap one exception


# Maximum number of results returned per page.
#
bookNumber = 1
def book_number():
   global bookNumber
   bookNumber += 1
   return bookNumber 

exceptions = 0
def another_exception():
   global exceptions
   exceptions += 1
   return exceptions

def get_lowest_price(book ):
	"""Finds out what the lowest price is for a book """
	#prices = #get a list of prices for the particular book

	if len(prices) > 0:
		return sorted(prices)[0]
	else: 
		return None
	
	

def get_bargain(book, discount):
	"""Tells you if the book is available at the price k"""
	try:
		if (not hasattr(book, "UsedPrice") or not hasattr(book, "OurPrice") ) :
			return None
		print "get_bargain: currently on book: '%s'  with amazon price %s and used price of %s" % (book.ProductName, book.OurPrice, book.UsedPrice) 
		amazon_price = float(string.lstrip(book.OurPrice, '$'))
		used_low_price =  float(string.lstrip(book.UsedPrice, '$'))
		discount  = float(discount)
		if  not (type(amazon_price) == float or type(used_low_price) == float or type(discount) == float):
			return None
		print "get_bargain: in numbers: amazon price = %f and used_low_price is %f" % (amazon_price, used_low_price)
		#lowest_marketplace_price = get_lowest_price(book)	
		#print "(discount * amazon_price) = %f" % (discount * amazon_price)

		if (used_low_price <= ((1.0 - discount) * amazon_price)): #do we have a good deal?
			savings = amazon_price - used_low_price
			savings_percent = (savings / amazon_price) * 100.00
			print "'%s' seems a good deal at '%s'. saving '%f' dollars and so '%f' percent off the amazon price '%s'. adding to list of good deals!" % (book.ProductName, book.UsedPrice, savings, savings_percent, book.OurPrice)
			return {'lowest_market_place_price': used_low_price,
				'savings' : savings,
				'savings_percent' : savings_percent
				#'seller' = seller #stub for including more info on the bargain
				}
		else:
			return None
	except Exception, e:
		print "get_bargain: an exception occured: '%s'" % e
		return None

def bargain_books(books,  page, discount=0.7):
	"""Tells you which of the passed list of books is discounted. 
	input: list of books
	output: list of dictionaries with the book object and the lowest price that meets the discount"""
	low_price_books = []
	print "bargain_books: number of books processing: %d" % len(books)
	for book in books: #for the book in this result page
		try:
			print "bargain_books: currently on book %d, '%s' on page %d" % (book_number(), book.ProductName, page)
			bargain = get_bargain(book, discount )
			if bargain != None: #is there a bargain available for this book? 
				low_price_books.append( {
					'book_title': book.ProductName, 
					'amazon_price': book.OurPrice,  
					'lowest_price': bargain['lowest_market_place_price'], 
					'savings' : bargain['savings'],
					'savings_percent' : bargain['savings_percent']})
    		except Exception, e: 
    			print "bargain_books: an exception occured '%s'" % e
			continue #skip that book
	return low_price_books
		

def checkWishList(amazonWishListID, discount=0.5):
    low_price_books = []
    pageNo = 1
    finished = False
    while not finished:
        try: 
        	books = amazon.searchByWishlist(amazonWishListID, page=pageNo) #we'll get 10 results per page
	except xml.parsers.expat.ExpatError, e:
		print "checkWishList: exception occured in page '%d': '%s' this is exception %d" % (pageNo, e, another_exception())
		print "exception type"	
		print  type(e)	
		#pageNo += 1
		continue
	print "checkWishList: page number: %d. length of books: %d" % (pageNo, len(books))
        low_price_books.extend(bargain_books(books,  pageNo, discount=discount ))
        pageNo += 1 #iterate until the end of the list
        if len(books)  <  3:
		finished = True
    print low_price_books
    print map(lambda book_data: book_data['book_title'], low_price_books)
   
def validate(options):
	assert  len(options['accessKey'])   > 0, 'no access key provided'	
	assert  len(options['wishlistIDs']) > 0, 'no wishlist ids provided'	
	assert re.search('0+\.\d+', options['discount']), 'discount not in the format (0.NNN...) it should be between 0.000 and 0.999' 
	 
def get_cl_options():
	clparser = optparse.OptionParser()
	#we have two ways of getting our options
	#through a file (more secure)	
	clparser.add_option("-o", "--options-file", dest="optionsfile",metavar="FILE",
				help="""put all your options in an options file. example file myAmazonOptions.conf:	#lines with # at start are ignored
amazonAccessKey=AB123AB123
amazonWishListIDs=RF123RF123
discount=0.5""")
	#through command line flags
	clparser.add_option("-d", "--discount", dest="discount", 
			   help="percent you want off to consider it a bargain. e.g.: 0.20 means anything at or above 20% off is a bargain (acceptable input is 0.0 to 1.0")
	clparser.add_option("-k", "--amazon-access-key", dest="accessKey",
				help="your secret amazon key" )
	clparser.add_option("-w", "--amazon-wishlist-ids", dest="wishlistIDs",
				help="comma delimited list of wishlists")
	(options, args) = clparser.parse_args()
	#give precedence to options file. if it's there. we'll use it's options list and overwrite the ones in the command line
	if options.optionsfile != None:
		file_object = open(options.optionsfile)
		try:
			options = conf_file.readConf(options.optionsfile)
		finally:
			file_object.close()
	#validate(options) #if there's no valid data. that's the end of the line
	return options
			
#script run starts here
MAX_RESULTS = 10 
if __name__ == "__main__":
    options = get_cl_options() #get the command line options
    amazon.setLicense(options['accessKey']) #set up the API to authenticate with my acces key
    for wishList in options['wishlistIDs'].split(","):
        checkWishList(wishList, options['discount'])
	pass
